package com.fjec.market.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fjec.common.shiro.AccountInfo;
import com.fjec.common.util.DateUtil;
import com.fjec.common.util.JsonUtil;
import com.fjec.common.util.NumberUtil;
import com.fjec.common.util.SpecialMapUtil;
import com.fjec.common.view.AnnexBizItem;
import com.fjec.market.entity.*;
import com.fjec.market.es.document.SpuDocument;
import com.fjec.market.es.repository.SpuRepository;
import com.fjec.market.feign.BaseClient;
import com.fjec.market.mapper.InfoMarketMapper;
import com.fjec.market.service.*;
import com.fjec.market.view.MarketIndexVO;
import com.fjec.market.view.MarketVO;
import com.fjec.market.view.ShopVO;
import org.apache.commons.collections.MapUtils;
import org.apache.shiro.SecurityUtils;
import org.elasticsearch.common.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 001.市场表 服务实现类
 * </p>
 *
 * @author admin
 * @since 2020-09-07
 */
@Service
@Transactional
public class InfoMarketServiceImpl extends ServiceImpl<InfoMarketMapper, InfoMarket> implements IInfoMarketService {

    @Resource
    private InfoMarketMapper mapper;

    @Resource
    private IInfoFarmerService infoFarmerService;

    @Resource
    private IInfoBusinessService infoBusinessService;

    @Resource
    private IInfoPurchaseService infoPurchaseService;

    @Resource
    private IBizPurchasingService bizPurchasingService;

    @Autowired
    private IInfoMarketSectionService infoMarketSectionService;

    @Resource
    private IInfoPersonalService infoPersonalService;

    @Resource
    private IBizMarketBusiService bizMarketBusiService;

    @Resource
    private IBizVisitBusinessRecordService bizVisitBusinessRecordService;

    @Autowired
    private IBizFollowService bizFollowService;

    @Autowired
    private IInfoSkuService infoSkuService;

    @Autowired
    private SpuRepository spuRepository;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    @Cacheable(value = "marketsPage", key = "'fjec:market:marketsPage:' + #page.getCurrent() + '-' + #page.getSize()")
    public Map<String, Object> getMarkets(Page page) {
        Map<String, Object> result = new HashMap<>();
        IPage<InfoMarket> p = this.page(page, new QueryWrapper<InfoMarket>().eq("Display", 1).orderByAsc("Sort"));
        List<MarketVO> markets = new ArrayList<>();
        List<InfoMarket> records = p.getRecords();
        records.forEach(record -> {
            MarketVO marketVo = new MarketVO();
            BeanUtils.copyProperties(record, marketVo);
            String pic = (String) record.getMarkPics().get("markPic");
            marketVo.setMarkPic(pic);
            markets.add(marketVo);
        });
        result.put("markets", markets);
        result.put("total", p.getTotal());

        return result;
    }

    @Override
    public Map<String, Object> getDevopsMarkets(Page page) {
        Map<String, Object> result = new HashMap<>();
        IPage<InfoMarket> p = this.page(page, new QueryWrapper<InfoMarket>().orderByDesc("Display").orderByAsc("Sort"));
        List<MarketVO> markets = new ArrayList<>();
        List<InfoMarket> records = p.getRecords();
        records.forEach(record -> {
            MarketVO marketVo = new MarketVO();
            BeanUtils.copyProperties(record, marketVo);
            String pic = (String) record.getMarkPics().get("markPic");
            marketVo.setMarkPic(pic);
            markets.add(marketVo);
        });
        result.put("markets", markets);
        result.put("total", p.getTotal());

        return result;
    }

    @Override
    public boolean updateMarketRotation(Integer markCode, List<Map<String, Object>> marketRotation) {
        boolean result = false;
        QueryWrapper<InfoMarket> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("MarkCode", markCode);
        InfoMarket entity = mapper.selectOne(queryWrapper);
        if (entity != null) {
            if (entity.getMarkPics() != null)
                if (entity.getMarkPics().containsKey("markLoopPics")) {
                    entity.getMarkPics().replace("markLoopPics", marketRotation);
                } else {
                    entity.getMarkPics().put("markLoopPics", marketRotation);
                }
            result = this.updateById(entity);
        }
        return result;
    }

    @Override
    public int saveMarketDevOps(InfoMarket infoMarket, String markPic, String markMapPic) {

        Map<String, Object> m = new HashMap<>();
        m.put("markPic", markPic);
        m.put("markMapPic", markMapPic);
        infoMarket.setMarkPics(m);

        boolean success;
        if (infoMarket.getId() == null || infoMarket.getId() == 0) {
            Integer maxMarkCode = mapper.getMaxMarkCode();
            if (maxMarkCode == null || maxMarkCode == 0)
                maxMarkCode = 10003;
            Long markCode = NumberUtil.giveUpNum(maxMarkCode + 1, 4);
            infoMarket.setMarkCode(Math.toIntExact(markCode));
            infoMarket.setCreateTime(DateUtil.nowLdt());
            infoMarket.setPlateValue(63);
//            infoMarket.setDisplay(1);
            success = this.save(infoMarket);
        } else {
            infoMarket.setUpdateTime(DateUtil.nowLdt());
            InfoMarket thisMarket = this.getById(infoMarket.getId());
            List<String> markLoopPics = (List<String>) thisMarket.getMarkPics().get("markLoopPics");
            m.put("markLoopPics", markLoopPics);
            success = this.updateById(infoMarket);
        }

        if (success) {
            Set<String> keys = redisTemplate.keys("fjec:market:" + "*");
            redisTemplate.delete(keys);
            return 0;
        } else
            return -1;
    }

    @Override
    @Cacheable(cacheNames = "marketsPage", key = "'fjec:market:marketIndex:' + #markCode")
    public Map<String, Object> getMarketByCode(Integer markCode) {
        List<Map<String, Object>> marketSections = infoMarketSectionService.listOfMap();
        InfoMarket infoMarket = this.getOne(new QueryWrapper<InfoMarket>().eq("MarkCode", markCode));

        MarketIndexVO marketIndexVO = new MarketIndexVO();
        BeanUtils.copyProperties(infoMarket, marketIndexVO);

        marketIndexVO.setMarkLoopPics(infoMarket.getMarkPics().get("markLoopPics"));

        int marketSectionValue = infoMarket.getPlateValue();

        List<Map<String, Object>> sections = new ArrayList<>();
        marketSections.forEach(s -> {
            int sectionVal = (int) s.get("sectionVal");
            int r = sectionVal & marketSectionValue;
            if (r != 0) sections.add(s);
        });

        marketIndexVO.setSections(sections);

        ObjectMapper om = new ObjectMapper();
        return om.convertValue(marketIndexVO, Map.class);
    }

    @Override
    @Cacheable(cacheNames = "c_1", key = "'fjec:market:shops:' + #markCode + ':' + #sectionVal + ':' + #page.getCurrent() + '-' + #page.getSize()")
    public Map<String, Object> getSectionBusinesses(Integer markCode, int sectionVal, Page page) {
        List<ShopVO> tshops;
        if (sectionVal == 1)
            tshops = getFarmer(markCode, page);
        else if (sectionVal == 2 || sectionVal == 4 || sectionVal == 8)
            tshops = getBusiness(markCode, sectionVal, page);
        else
            tshops = getPurchase(markCode, page);

        List<Map<String, Object>> shops = tshops.stream().map(ShopVO::toMap).collect(Collectors.toList());
        Long total = page.getTotal();
        Map<String, Object> result = new HashMap<>();
        result.put("shops", shops);
        result.put("total", total);
        return result;
    }

    public List<ShopVO> getFarmer(Integer markCode, Page page) {
        List<InfoFarmer> farmers = infoFarmerService.getFarmerByMarkCode(markCode, page);
        return extendFarmer(farmers, 0L, true);
    }

    @Override
    public List<ShopVO> extendFarmer(List<InfoFarmer> farmers, Long userId, boolean top2) {
        if (farmers.size() == 0)
            return new ArrayList<>();

        List<ShopVO> farmerVOs = new ArrayList<>();
        List<Long> farmerIds = new ArrayList<>();

        farmers.forEach(farmer -> {
            ShopVO farmerVO = new ShopVO();
            BeanUtils.copyProperties(farmer, farmerVO);
            farmerVO.setBusiType(2);

            farmerVOs.add(farmerVO);
            farmerIds.add(farmer.getId());
        });
        if (farmerVOs.size() == 0) return farmerVOs;

        List<Map<String, Object>> skus;
        if (top2) {
            skus = infoSkuService.getTop2SkusByShopIds(farmerIds);
        } else {
            skus = infoSkuService.getSkusByShopIds(farmerIds);
        }

        Map<Long, List<Map<String, Object>>> skuMap = new HashMap<>();
        skus.forEach(sku -> {
            Long busiId = MapUtils.getLong(sku, "BusiId");
            if (skuMap.get(busiId) == null) skuMap.put(busiId, new ArrayList<>());
            sku = SpecialMapUtil.lowKey(sku);
            sku.put("busiId", String.valueOf(sku.get("busiId")));
            sku.put("spuId", String.valueOf(sku.get("spuId")));
            sku.put("spuPics", JsonUtil.jsonToObject(sku.get("spuPics").toString(), List.class));
            skuMap.get(busiId).add(sku);
        });

        farmerVOs.forEach(farmerVO -> farmerVO.setSkus(skuMap.get(farmerVO.getId())));

        return farmerVOs;
    }


    public List<ShopVO> getBusiness(Integer markCode, int sectionVal, Page page) {
        List<InfoBusiness> businesses;
        Integer busiType = 0;
        if (sectionVal == 2)
            busiType = 3;
        else if (sectionVal == 4)
            busiType = 5;
        else
            busiType = 4;
        businesses = infoBusinessService.getBusinessByMarkIdAndBusiType(markCode, busiType, page);
        return extendBusiness(businesses, 0L, true);
    }

    @Override
    public List<ShopVO> extendBusiness(List<InfoBusiness> businesses, Long userId, boolean top2) {
        if (businesses.size() == 0)
            return new ArrayList<>();

        List<ShopVO> businessVOs = new ArrayList<>();
        List<Long> businessIds = new ArrayList<>();

        businesses.forEach(business -> {
            ShopVO businessVO = new ShopVO();
            BeanUtils.copyProperties(business, businessVO);
            businessVO.setBusiType(business.getBusiType());

            businessVOs.add(businessVO);
            businessIds.add(business.getId());
        });
        if (businessVOs.size() == 0) return businessVOs;

        List<Map<String, Object>> skus;
        if (top2) {
            skus = infoSkuService.getTop2SkusByShopIds(businessIds);
        } else {
            skus = infoSkuService.getSkusByShopIds(businessIds);
        }
        Map<Long, List<Map<String, Object>>> skuMap = new HashMap<>();
        skus.forEach(sku -> {
            Long busiId = MapUtils.getLong(sku, "BusiId");
            if (skuMap.get(busiId) == null) skuMap.put(busiId, new ArrayList<>());
            sku = SpecialMapUtil.lowKey(sku);
            sku.put("busiId", String.valueOf(sku.get("busiId")));
            sku.put("spuId", String.valueOf(sku.get("spuId")));
            sku.put("spuPics", JsonUtil.jsonToObject(sku.get("spuPics").toString(), List.class));
            skuMap.get(busiId).add(sku);
        });

        businessVOs.forEach(farmerVO -> farmerVO.setSkus(skuMap.get(farmerVO.getId())));
        return businessVOs;
    }

    public List<ShopVO> getPurchase(Integer markCode, Page page) {
        List<InfoPurchase> purchases = infoPurchaseService.getInfoPurchaseByMarkCode(markCode, page);

        return extendPurchase(purchases, 0L, true);
    }

    @Override
    public List<ShopVO> extendPurchase(List<InfoPurchase> purchases, Long userId, boolean top2) {
        if (purchases.size() == 0)
            return new ArrayList<>();

        List<ShopVO> purchaseVOs = new ArrayList<>();
        List<Long> purchaseIds = new ArrayList<>();

        purchases.forEach(purchase -> {
            ShopVO purchaseVO = new ShopVO();
            BeanUtils.copyProperties(purchase, purchaseVO);
            purchaseVO.setBusiType(6);

            purchaseVOs.add(purchaseVO);
            purchaseIds.add(purchase.getId());
        });
        if (purchaseVOs.size() == 0) return purchaseVOs;

        List<BizPurchasing> purchasings;
        if (top2) {
            purchasings = bizPurchasingService.get2PurchasingByPurchaseIds(purchaseIds);
        } else {
            purchasings = bizPurchasingService.getPurchasingByPurchaseIds(purchaseIds);
        }

        Map<Long, List<BizPurchasing>> purchasingMap = new HashMap<>();
        purchasings.forEach(purchasing -> {
            Long purcId = purchasing.getPurcId();
            purchasingMap.computeIfAbsent(purcId, k -> new ArrayList<>());
            purchasingMap.get(purcId).add(purchasing);
        });

        purchaseVOs.forEach(purchaseVO -> purchaseVO.setPurchasingDetail(purchasingMap.get(purchaseVO.getId())));

        return purchaseVOs;
    }

    @Override
    public List<Map<String, Object>> getProducts(int markCode, int busiType, String title, int orderBy, int dir, Page page) {
        List<Map<String, Object>> skus;
        List<Long> spuIds = new ArrayList<>();

        if (title != null) {
            List<SpuDocument> spuDocuments = spuRepository.findBySpuTitle(title);
            spuIds = spuDocuments.stream().map(SpuDocument::getId).collect(Collectors.toList());
        }

        skus = infoSkuService.getSkusBySpuIDsAndMarkCodeAndBusiType(markCode, busiType, spuIds, orderBy, dir, page);
        List result = new ArrayList();
        skus.forEach(m -> {
            String pics = MapUtils.getString(m, "SpuPics");
            m.put("SpuPics", JsonUtil.jsonToObject(pics, List.class));
            String vids = MapUtils.getString(m, "SpuVideos");
            m.put("SpuVideos", JsonUtil.jsonToObject(vids, List.class));
            result.add(SpecialMapUtil.lowKey(m));
        });
        return result;
    }

    @Override
    public InfoSku getProductById(Long id) {
        if (id != null) {
            return infoSkuService.getById(id);
        }
        return null;
    }

    @Override
    public ShopVO getShopIndexById(Long id, Integer busiType) {
        ShopVO shopVO;

        Long userId = 0L;
        if (SecurityUtils.getSubject().isAuthenticated())
            userId = AccountInfo.getUserId();

        if (busiType == 2) {
            InfoFarmer farmerShop = infoFarmerService.getById(id);
            List<InfoFarmer> farmers = new ArrayList<>();
            farmers.add(farmerShop);

            shopVO = extendFarmer(farmers, userId, false).get(0);
            int totalSales = infoSkuService.sumSkuSaleNumByBusiId(shopVO.getId());
            String shopNumStr = String.valueOf(farmerShop.getShopNum());
            String shopNum = shopNumStr.substring(0, 2) + "-" + shopNumStr.substring(2);
            shopVO.setShopNum(shopNum);
            shopVO.setTotalSales(totalSales);

        } else if (busiType == 3 || busiType == 4 || busiType == 5) {
            InfoBusiness businessShop = infoBusinessService.getById(id);
            List<InfoBusiness> businesses = new ArrayList<>();
            businesses.add(businessShop);
            shopVO = extendBusiness(businesses, userId, false).get(0);
            String shopNumStr = String.valueOf(businessShop.getShopNum());
            String shopNum = shopNumStr.substring(0, 2) + "-" + shopNumStr.substring(2);
            shopVO.setShopNum(shopNum);
            int totalSales = infoSkuService.sumSkuSaleNumByBusiId(shopVO.getId());
            shopVO.setTotalSales(totalSales);
        } else {
            InfoPurchase purchaseShop = infoPurchaseService.getById(id);
            List<InfoPurchase> purchases = new ArrayList<>();
            purchases.add(purchaseShop);
            shopVO = extendPurchase(purchases, userId, false).get(0);
            String shopNumStr = String.valueOf(purchaseShop.getShopNum());
            String shopNum = shopNumStr.substring(0, 2) + "-" + shopNumStr.substring(2);
            shopVO.setShopNum(shopNum);
        }

        // 关注信息
        Long thisUserId = SecurityUtils.getSubject().isAuthenticated() ? AccountInfo.getUserId() : null;
        if (thisUserId != null && thisUserId != 0) {
            List<BizFollow> follows = bizFollowService.list(new QueryWrapper<BizFollow>().eq("UserId", thisUserId));
            List<Long> followingIds = follows.stream().map(BizFollow::getBusiId).collect(Collectors.toList());
            if (followingIds.size() > 0) {
                shopVO.setFollowed(followingIds.contains(shopVO.getId()));
            }
        }

        // 写店铺访问记录表
        if (userId != 0) {
            BizVisitBusinessRecord record = new BizVisitBusinessRecord();
            record.setBusiId(id);
            record.setBusiType(busiType);
            record.setUserId(userId);
            record.setCreateTime(DateUtil.nowLdt());
            bizVisitBusinessRecordService.save(record);
        }
        // end

        return shopVO;
    }


    @Override
    public Map<String, Object> getSessionInfo(Long userId, int busiType) {
        Map<String, Object> m = new HashMap<>();
        InfoPersonal personal = infoPersonalService.getOne(new QueryWrapper<InfoPersonal>().eq("UserId", userId));
        m.put("WxNickName", personal.getNickName());
        if (busiType == 1) {
            m.put("BusiId", personal.getId());
            m.put("HeadPic", personal.getHeadPic());
        } else if (busiType == 2) {
            InfoFarmer farmer = infoFarmerService.getOne(new QueryWrapper<InfoFarmer>().eq("UserId", userId));
            m.put("BusiId", farmer.getId());
            m.put("ShopName", farmer.getShopName());
            if (Strings.isNullOrEmpty(farmer.getCompHeadPic())) {
                m.put("HeadPic", personal.getHeadPic());
            } else {
                m.put("HeadPic", farmer.getCompHeadPic());
            }
        } else if (busiType == 3 || busiType == 4 || busiType == 5) {
            InfoBusiness business = infoBusinessService.getOne(new QueryWrapper<InfoBusiness>().eq("UserId", userId));
            m.put("BusiId", business.getId());
            m.put("ShopName", business.getShopName());
            if (Strings.isNullOrEmpty(business.getCompHeadPic())) {
                m.put("HeadPic", personal.getHeadPic());
            } else {
                m.put("HeadPic", business.getCompHeadPic());
            }
        } else if (busiType == 6) {
            InfoPurchase purchase = infoPurchaseService.getOne(new QueryWrapper<InfoPurchase>().eq("UserId", userId));
            m.put("BusiId", purchase.getId());
            m.put("ShopName", purchase.getShortName());
            if (Strings.isNullOrEmpty(purchase.getCompHeadPic())) {
                m.put("HeadPic", personal.getHeadPic());
            } else {
                m.put("HeadPic", purchase.getCompHeadPic());
            }
        }
        return m;
    }

    @Override
    public Map<String, Object> getSessionInfoByUserId(Long userId) {
        Map<String, Object> resultMap = new HashMap<>();
        InfoPersonal personal = infoPersonalService.getOne(new QueryWrapper<InfoPersonal>().eq("UserId", userId));
        resultMap.put("WxNickName", personal.getNickName());
        resultMap.put("BusiType", personal.getBusiType());
        switch (personal.getBusiType()) {
            case 1:
                resultMap.put("BusiId", personal.getId());
                resultMap.put("HeadPic", personal.getHeadPic());
                break;
            case 2:
                InfoFarmer farmer = infoFarmerService.getOne(new QueryWrapper<InfoFarmer>().eq("UserId", userId));
                resultMap.put("BusiId", farmer.getId());
                resultMap.put("ShopName", farmer.getShopName());
                if (Strings.isNullOrEmpty(farmer.getCompHeadPic())) {
                    resultMap.put("HeadPic", personal.getHeadPic());
                } else {
                    resultMap.put("HeadPic", farmer.getCompHeadPic());
                }
                break;
            case 3:
            case 4:
            case 5:
                InfoBusiness business = infoBusinessService.getOne(new QueryWrapper<InfoBusiness>().eq("UserId", userId));
                resultMap.put("BusiId", business.getId());
                resultMap.put("ShopName", business.getShopName());
                if (Strings.isNullOrEmpty(business.getCompHeadPic())) {
                    resultMap.put("HeadPic", personal.getHeadPic());
                } else {
                    resultMap.put("HeadPic", business.getCompHeadPic());
                }
                break;
            case 6:
                InfoPurchase purchase = infoPurchaseService.getOne(new QueryWrapper<InfoPurchase>().eq("UserId", userId));
                resultMap.put("BusiId", purchase.getId());
                resultMap.put("ShopName", purchase.getShortName());
                if (Strings.isNullOrEmpty(purchase.getCompHeadPic())) {
                    resultMap.put("HeadPic", personal.getHeadPic());
                } else {
                    resultMap.put("HeadPic", purchase.getCompHeadPic());
                }
                break;
        }
        return resultMap;
    }

    @Override
    public List<ShopVO> getFarmerSkuByIds(List<Long> followingShopIds) {
        List<InfoFarmer> farmers = infoFarmerService.list(new QueryWrapper<InfoFarmer>().in("Id", followingShopIds));
        return extendFarmer(farmers, AccountInfo.getUserId(), true);
    }

    @Override
    public List<ShopVO> getPurchaseByIds(List<Long> followingShopIds) {
        List<InfoPurchase> purchases = infoPurchaseService.list(new QueryWrapper<InfoPurchase>().in("Id", followingShopIds));
        return extendPurchase(purchases, AccountInfo.getUserId(), true);
    }

    @Override
    public List<ShopVO> getBusinessSkuByIds(List<Long> followingShopIds) {
        List<InfoBusiness> businesses = infoBusinessService.list(new QueryWrapper<InfoBusiness>().in("Id", followingShopIds));
        return extendBusiness(businesses, AccountInfo.getUserId(), true);
    }

    @Override
    public List<ShopVO> getMyFollowing(Long userId, Integer busiType, Page page) {
        List<BizFollow> bizFollows = bizFollowService.page(page, new QueryWrapper<BizFollow>().eq("UserId", userId).eq("BusiType", busiType)).getRecords();
        if (bizFollows.size() == 0) return new ArrayList<>();
        List<Long> followingShopIds = bizFollows.stream().map(BizFollow::getBusiId).collect(Collectors.toList());
        List<ShopVO> result;
        if (busiType == 2)
            result = this.getFarmerSkuByIds(followingShopIds);
        else if (busiType == 6)
            result = this.getPurchaseByIds(followingShopIds);
        else
            result = this.getBusinessSkuByIds(followingShopIds);

        result.forEach(shop -> shop.setFollowed(true));
        return result;
    }

    @Override
    public List<ShopVO> getShopVOsByBusiIds(List<Long> busiIds, Long userId) {
        List<ShopVO> finalResult = new ArrayList<>();

        List<InfoFarmer> farmers = infoFarmerService.listByIds(busiIds);
        finalResult.addAll(extendFarmer(farmers, userId, true));

        List<InfoBusiness> businesses = infoBusinessService.listByIds(busiIds);
        finalResult.addAll(extendBusiness(businesses, userId, true));

        List<InfoPurchase> purchases = infoPurchaseService.listByIds(busiIds);
        finalResult.addAll(extendPurchase(purchases, userId, true));

        // 关注信息
        if (userId != null && userId != 0) {
            List<BizFollow> follows = bizFollowService.list(new QueryWrapper<BizFollow>().eq("UserId", userId));
            List<Long> followingIds = follows.stream().map(BizFollow::getBusiId).collect(Collectors.toList());
            if (followingIds.size() > 0) {
                finalResult.forEach(m -> m.setFollowed(followingIds.contains(m.getId())));
            }
        }

        return finalResult;
    }

    @Override
    public List<ShopVO> getShopVOsByGivingUserIds(List<Long> givingUserIds, Long userId) {
        List<ShopVO> finalResult = new ArrayList<>();

        List<InfoFarmer> farmers = infoFarmerService.list(new QueryWrapper<InfoFarmer>().in("UserId", givingUserIds));
        finalResult.addAll(extendFarmer(farmers, userId, true));

        List<InfoBusiness> businesses = infoBusinessService.list(new QueryWrapper<InfoBusiness>().in("UserId", givingUserIds));
        finalResult.addAll(extendBusiness(businesses, userId, true));

        List<InfoPurchase> purchases = infoPurchaseService.list(new QueryWrapper<InfoPurchase>().in("UserId", givingUserIds));
        finalResult.addAll(extendPurchase(purchases, userId, true));

        // 关注信息
        if (userId != null && userId != 0) {
            List<BizFollow> follows = bizFollowService.list(new QueryWrapper<BizFollow>().eq("UserId", userId));
            List<Long> followingIds = follows.stream().map(BizFollow::getBusiId).collect(Collectors.toList());
            if (followingIds.size() > 0) {
                finalResult.forEach(m -> m.setFollowed(followingIds.contains(m.getId())));
            }
        }

        return finalResult;
    }

    @Override
    public List<InfoMarket> getMarketsByBusiId(Long busiId) {
        return mapper.getMarketsByBusiId(busiId);
    }

    @Override
    @Cacheable(cacheNames = "c_3", key = "'fjec:market:retailFruits:' + #markCode + ':' + #orderBy + ':' + #dir + ':' + #page.getCurrent() + '-' +#page.getSize()")
    public List<Map<String, Object>> getRetailFruits(Integer markCode, Integer orderBy, Integer dir, Page page) {
        List<Map<String, Object>> result = infoSkuService.getRetailFruits(markCode, new ArrayList<>(), orderBy, dir, page);
        result.forEach(m -> {
            String pics = MapUtils.getString(m, "SpuPics");
            m.put("SpuPics", JsonUtil.jsonToObject(pics, List.class));
            String vids = MapUtils.getString(m, "SpuVideos");
            m.put("SpuVideos", JsonUtil.jsonToObject(vids, List.class));
        });
        return result;
    }

    @Override
    @Cacheable(cacheNames = "marketsPage", key = "'fjec:market:allMarketLocation'")
    public List<Map<String, Object>> getAllMarketLocation() {
        List<Map<String, Object>> result = new ArrayList<>();
        List<InfoMarket> markets = this.list(new QueryWrapper<InfoMarket>().eq("Display", 1));
        markets.forEach(m -> {
            Map<String, Object> market = new HashMap<>();
            market.put("id", m.getMarkCode());
            market.put("iconPath", m.getMarkPics().get("markMapPic"));
            market.put("markName", m.getMarkName());
            market.put("latitude", m.getLatitude());
            market.put("longitude", m.getLongitude());
            market.put("width", 112);
            market.put("height", 112);
            result.add(market);
        });
        return result;
    }

    @Override
    @Cacheable(cacheNames = "marketsPage", key = "'fjec:market:marketsHavingSection:' + #sectionVal")
    public List<InfoMarket> getMarketsHavingSection(Integer sectionVal) {
        List<InfoMarket> markets = this.list(new QueryWrapper<InfoMarket>().eq("Display", 1));
        Iterator<InfoMarket> iterator = markets.iterator();
        while (iterator.hasNext()) {
            InfoMarket market = iterator.next();
            Integer plateVal = market.getPlateValue();
            if ((plateVal & sectionVal) == 0) iterator.remove();
        }
        return markets;
    }

    @Override
    @Cacheable(cacheNames = "marketsPage", key = "'fjec:market:marketLocation:' + #markCode")
    public Map<String, Object> getMarketLocation(Integer markCode) {
        InfoMarket market = this.getOne(new QueryWrapper<InfoMarket>().eq("MarkCode", markCode));
        Map<String, Object> result = new HashMap<>();
        result.put("longitude", market.getLongitude());
        result.put("latitude", market.getLatitude());
        return result;
    }

    @Override
    public List<Integer> getMarkCodesByBusiId(Long busiId, Integer busiType) {
        List<BizMarketBusi> bizMarketBusiList = bizMarketBusiService.list(new QueryWrapper<BizMarketBusi>()
                .eq("BusiId", busiId).eq("BusiType", busiType));
        return bizMarketBusiList.stream().map(BizMarketBusi::getMarkCode).collect(Collectors.toList());
    }
}
